<html>
  <head>
    <meta charset="utf-8" />
    <title>Open3D WebVisualizer</title>
    <link rel="stylesheet" type="text/css" href="styles.css" />
    <link rel="icon" type="image/ico" href="open3d_logo.ico" />
    <script src="libs/adapter.min.js"></script>
    <script src="webrtcstreamer.js"></script>
    <script>
      /**
       * Global WebRTC configs.
       */
      let webRtcOptions = "rtptransport=tcp&timeout=60";

      /**
       * WebRTC connections.
       */
      let webRtcServerList = {};

      /**
       * Get the div where to insert a video.
       */
      function getContentDiv() {
        let contentDiv = document.getElementById("content");
        return contentDiv;
      }

      function setDifference(setA, setB) {
        let _difference = new Set(setA);
        for (let elem of setB) {
          _difference.delete(elem);
        }
        return _difference;
      }

      /**
       * Init device list
       * @param {object} mediaList A map of media. E.g.
       * let mediaList = {
       *  0: {video: "window_0"},
       *  1: {video: "window_1"},
       * }
       */
      function updateMediaList(mediaList) {
        // Create navigation menu.
        let menu = document.getElementById("menu");

        // The current video source that the server is serving.
        let validWindowIds = new Set();
        for (let key in mediaList) {
          validWindowIds.add(mediaList[key].video);
        }

        // Collect stale and new URLs. Avoid "removing while iterating".
        let existingWindowIds = new Set();
        let staleWindowIds = new Array();
        for (let i = 0; i < menu.children.length; i++) {
          let navElt = menu.children[i];
          let windowId = navElt.windowId;
          existingWindowIds.add(windowId);
          if (!validWindowIds.has(windowId)) {
            staleWindowIds.push(windowId);
          }
        }
        let newWindowIds = [
          ...setDifference(validWindowIds, existingWindowIds),
        ];

        // Remove stale URLs.
        staleWindowIds.forEach(function (windowId) {
          let videoId = "video_" + windowId;
          let id = "nav_" + videoId;
          document.getElementById(id).remove();
        });

        // Append new URLs to the menu bar.
        newWindowIds.forEach(function (windowId) {
          let videoId = "video_" + windowId;
          let navId = "nav_" + videoId;
          let navElt = document.createElement("a");
          navElt.text = windowId;
          navElt.windowId = windowId;
          navElt.id = navId;
          navElt.onclick = function () {
            if (this.className === "active") {
              delConnection(this.windowId);
            } else {
              addConnection(this.windowId);
            }
          };
          menu.appendChild(navElt);
        });

        // Connect to the new URLs, this will also highlight the menu entry.
        newWindowIds.forEach((windowId) => {
          addConnection(windowId);
        });
      }

      /**
       * Delete a WebRTC client connection.
       */
      function delConnection(windowId) {
        console.log("delConnection: ", windowId);
        let videoId = "video_" + windowId;

        // Disconnect WebRTC connection.
        let webrtcServer = webRtcServerList[videoId];
        if (webrtcServer) {
          webrtcServer.disconnect();
          webRtcServerList[videoId] = undefined;
        }
      }

      /**
       * Add a WebRTC client connection.
       */
      function addConnection(windowId) {
        let videoId = "video_" + windowId;

        // Add a video element to display WebRTC stream.
        if (document.getElementById(videoId) === null) {
          let contentDiv = getContentDiv();
          if (contentDiv) {
            let divElt = document.createElement("div");
            divElt.id = "div_" + videoId;

            let nameElt = document.createElement("h2");
            nameElt.id = "title_" + videoId;
            nameElt.innerHTML = "<div>" + windowId + "</div>";
            divElt.appendChild(nameElt);

            let videoElt = document.createElement("video");
            videoElt.id = videoId;
            videoElt.title = windowId;
            videoElt.muted = true;
            videoElt.controls = false;
            videoElt.playsinline = true;
            videoElt.innerText = "Your browser does not support HTML5 video.";

            divElt.appendChild(videoElt);
            contentDiv.appendChild(divElt);
          }
        }

        let videoElt = document.getElementById(videoId);
        if (videoElt) {
          let onClose = function () {
            console.log("onClose() called for videoId:", videoId);

            // Remove the video element and its tile.
            let divElt = document.getElementById("div_" + videoId);
            divElt.parentElement.removeChild(divElt);

            // Un-highlight the navigation.
            let navElt = document.getElementById("nav_" + videoId);
            navElt.className = "";

            WebRtcStreamer.getMediaList()
              .then((response) => response.json())
              .then((response) => updateMediaList(response));
          };

          // Connect video element to WebRTC stream.
          let webRtcClient = new WebRtcStreamer(videoId, "", onClose, null);
          console.log("[addConnection] videoId: " + videoId);

          webRtcClient.connect(windowId, /*audio*/ null, webRtcOptions);
          console.log("[addConnection] windowId: " + windowId);
          console.log("[addConnection] options: " + webRtcOptions);

          // Highlight the navigation.
          let navElt = document.getElementById("nav_" + videoId);
          navElt.className = "active";

          // Register WebRTC streamer connection.
          webRtcServerList[videoId] = webRtcClient;
        }
      }

      /**
       * Load/unload callbacks.
       */
      window.onload = function () {
        WebRtcStreamer.getMediaList()
          .then((response) => response.json())
          .then((response) => updateMediaList(response));
      };
      window.onbeforeunload = function () {
        for (let key in webRtcServerList) {
          webRtcServerList[key].disconnect();
        }
      };
    </script>
  </head>

  <body>
    <nav id="menu"></nav>
    <div id="content"></div>
    <footer id="footer"></footer>
  </body>
</html>
